﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace LunarPhase.Model
{
    /// <summary>
    /// Main calculation here! 
    /// These are based on the public domain utilites published by
    /// Michael Erlwine in Manual of Computer Programming for Astrologers,1980
    /// </summary>
    public class MoonSignCalculator
    {
        private const int M = 3600;

        private double FNp(double x)
        {
            double sgn = 0;
            if (x < 0)
            {
                sgn = -1;
            }
            else
            {
                sgn = 1;
            }

            return sgn * ((Math.Abs(x) / M) / 360 - Math.Floor((Math.Abs(x) / M) / 360)) * 360;
        }

        private double FNu(double x)
        {
            return x - (Math.Floor(x / 360) * 360);
        }

        private double FNr(double x)
        {
            return Math.PI / 180 * x;
        }

        private double FNs(double x)
        {
            return Math.Sin(Math.PI / 180 * x);
        }

        public Zodiac Calculate(DateTime date, int hourTimeZone)
        {
            var d = date.Day;

            var m = date.Month;

            var y = date.Year;

            var hr = date.Hour;

            var mi = date.Minute;

            // am=Number(document.getElementById("inputform").ampm.value)
            var zone = hourTimeZone; //TimeZoneInfo.Local.BaseUtcOffset.Hours;
            var f = hr + (mi / 60) - zone;

            var im = 12 * (y + 4800) + m - 3;
            var j = (2 * (im - Math.Floor(im / 12) * 12) + 7 + 365 * im) / 12;
            j = Math.Floor(j) + d + Math.Floor(im / 48) - 32083;
            var jd = j + Math.Floor(im / 4800) - Math.Floor(im / 1200) + 38;
            var T = ((jd - 2415020) + f / 24 - .5) / 36525;
            var ob = FNr(23.452294 - .0130125 * T);

            var ll = 973563 + 1732564379 * T - 4 * T * T;
            var g = 1012395 + 6189 * T;
            var n = 933060 - 6962911 * T + 7.5 * T * T;
            var g1 = 1203586 + 14648523 * T - 37 * T * T;
            d = (int)(1262655 + 1602961611 * T - 5 * T * T);

            var l = (ll - g1) / M;
            var l1 = ((ll - d) - g) / M;
            f = (int)((ll - n) / M);
            d = d / M;
            y = 2 * d;
            var ml = 22639.6 * FNs(l) - 4586.4 * FNs(l - y);
            ml = ml + 2369.9 * FNs(y) + 769 * FNs(2 * l) - 669 * FNs(l1);
            ml = ml - 411.6 * FNs(2 * f) - 212 * FNs(2 * l - y);
            ml = ml - 206 * FNs(l + l1 - y) + 192 * FNs(l + y);
            ml = ml - 165 * FNs(l1 - y) + 148 * FNs(l - l1) - 125 * FNs(d);
            ml = ml - 110 * FNs(l + l1) - 55 * FNs(2 * f - y);
            ml = ml - 45 * FNs(l + 2 * f) + 40 * FNs(l - 2 * f);
            var tn = n + 5392 * FNs(2 * f - y) - 541 * FNs(l1) - 442 * FNs(y);
            tn = tn + 423 * FNs(2 * f) - 291 * FNs(2 * l - 2 * f);
            g = FNu(FNp(ll + ml));

            int sign = (int)Math.Floor(g / 30);
            var degree = (g - (sign * 30));
            sign++;

            // We now have the sign as 1 to 12 for the zodiac signs. 
            switch (sign)
            {
                case 1:
                    return Zodiac.Aries;
                case 2:
                    return Zodiac.Taurus;
                case 3:
                    return Zodiac.Gemini;
                case 4:
                    return Zodiac.Cancer;

                case 5:
                    return Zodiac.Leo;
                case 6:
                    return Zodiac.Virgo;
                case 7:
                    return Zodiac.Libra;
                case 8:
                    return Zodiac.Scorpio;
                case 9:
                    return Zodiac.Sagittarius;
                case 10:
                    return Zodiac.Capricorn;
                case 11:
                    return Zodiac.Aquarius;
                case 12:
                    return Zodiac.Pisces;
                default:
                    return Zodiac.Pisces;
            }

        }
    }
}
